package concurrent;


import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author fengpeng
 * @date 2019-08-15  15:36
 */
@Slf4j
public class ThreadPoolDemo {

    private ThreadPoolDemo(){}

    /**
     * the number of threads to keep in the pool,
     * even if they are idle, unless {@code allowCoreThreadTimeOut} is set
     */
    private static final int COREPOOLSIZE = 20;
    /**
     * the maximum number of threads to allow in the pool
     */
    private static final int MAXIMUMPOOLSIZE = 20;
    /**
     * when the number of threads is greater than
     * the core, this is the maximum time that excess idle threads
     * will wait for new tasks before terminating.
     */
    private static final long KEEPALIVETIME = 120L;

    /**
     * 队列长度
     */
    private static final int CAPACITY = 20480;
    /**
     * 自定义扩展线程池,通过类的加载方式实现单例
     * 使用自定义的线程工厂类
     */
    private static ExecutorService executorService = new ThreadPoolExecutor(
                    COREPOOLSIZE,
                    MAXIMUMPOOLSIZE,
                    KEEPALIVETIME,
                    TimeUnit.SECONDS,
                    new ArrayBlockingQueue<>(CAPACITY),
                    new DefaultThreadFactory(),
                    new ThreadPoolExecutor.DiscardOldestPolicy()
            ) {
                /**
                 * 准备执行
                 * @param t
                 * @param r
                 */
                @Override
                protected void beforeExecute(Thread t, Runnable r) {
                    log.info("准备执行：name={},Thread_id={}", t.getName(), t.getId());
                }

                /**
                 * 执行完成
                 * @param r
                 * @param t
                 */
                @Override
                protected void afterExecute(Runnable r, Throwable t) {
                    log.info("执行完成");
                }

                /**
                 * 线程池退出
                 */
                @Override
                protected void terminated() {
                    log.info("线程池退出");
                }

                @Override
                public void execute(Runnable command) {
                    super.execute(wrap(command, clientTrace(), Thread.currentThread().getName()));
                }

                private Exception clientTrace() {
                    return new Exception("线程池任务调度出现异常");
                }

                @Override
                public Future<?> submit(Runnable task) {
                    return super.submit(wrap(task, clientTrace(), Thread.currentThread().getName()));
                }

                /**
                 * 封装异常
                 * @param task
                 * @param clientStack
                 * @param clientThreadName
                 * @return
                 */
                private Runnable wrap(final Runnable task, final Exception clientStack, final String clientThreadName) {
                    return new Runnable() {
                        @Override
                        public void run() {
                            try {
                                task.run();
                            } catch (Exception e) {
                                log.error(e.getMessage(), e);
                                log.error("clientThreadName={}", clientThreadName, clientStack);
                                throw e;
                            }
                        }
                    };
                }
            };


    /**
     * 自定义扩展线程池,通过类的加载方式实现单例
     * 使用默认的工厂类
     */
    private static ExecutorService executorService2 = new ThreadPoolExecutor(
            COREPOOLSIZE,
            MAXIMUMPOOLSIZE,
            KEEPALIVETIME,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(CAPACITY),
            new ThreadPoolExecutor.DiscardOldestPolicy()
    );

    public static void execute(Runnable command){
        executorService2.execute(command);
    }

    public static void main(String[] args){



        for (int i = 0; i< 5; i++){
            

        }

    }


}
